package deviceController

import (
	"errors"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntity"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntityManager"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEnum/enumDataCommStatus"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEnum/enumOperateMode"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEnum/enumRecordData"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisRpc"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisService"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/GID"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"go-fox-edge-device/deviceLogger"
	"go-fox-edge-device/deviceScript"
	"net/http"
	"time"
)

type deviceReportController struct {
}

// Scheduler 创建一个线程
func (e *deviceReportController) Scheduler() {
	go e.scheduler()
}

// 线程函数
func (e *deviceReportController) scheduler() {
	// 创建一个线程ID
	routineKey := "Report:" + String.ToString(GID.Alloc())

	// 为当前线程，进行脚本引擎的初始化
	deviceScript.EngineInitialize.Initialize(routineKey)

	for true {
		time.Sleep(1 * time.Millisecond)

		e.execute(routineKey)
	}
}

func (e *deviceReportController) execute(routineKey string) {
	// 定义一个最终的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			deviceLogger.PrintLogger(fmt.Sprintf("deviceExecuteController.execute() 捕获到异常:%v", r))
		}
	}()

	// 检查：是否装载完毕
	if !commEntityManager.EntityManager.Initialized {
		time.Sleep(1 * time.Second)
		return
	}

	// 取出消息
	channelRespondVO, err := commRedisRpc.Channel.Client.Report.Pop(1 * time.Second)
	if err != nil {
		return
	}

	// 对数据进行解码处理
	e.decodeEvent(routineKey, channelRespondVO)

	return

}

func (e *deviceReportController) decodeEvent(routineKey string, channelRespondVO *commRedisRpc.ChannelRespondVO) {
	channelType := channelRespondVO.Type
	channelName := channelRespondVO.Name
	recv := channelRespondVO.Recv

	finder := func(entity commEntity.IEntity) bool {
		value := entity.(*edgeEntity.DeviceEntity)
		if value.ChannelName != channelName {
			return false
		}
		if value.ChannelType != channelType {
			return false
		}

		return true
	}

	// 查找数据
	deviceList := commRedisService.FindEntityList(edgeEntity.Type.DeviceEntity.Type(), finder)
	for _, value := range deviceList {
		entity := value.(*edgeEntity.DeviceEntity)

		// 新建一个Map，再从entity复制内容，防止影响到本地缓存
		param := make(map[string]interface{})
		Map.Append(param, entity.DeviceParam)

		// 数据解码
		respondVO, err := e.decodeReport(routineKey, entity, recv, param)
		if err != nil || respondVO == nil {
			continue
		}

		taskRespondVO := commRedisRpc.Type.TaskRespondVO.New()
		taskRespondVO.Uuid = respondVO.Uuid
		taskRespondVO.Timeout = respondVO.Timeout
		taskRespondVO.Code = http.StatusOK
		taskRespondVO.RespondVOS = append(taskRespondVO.RespondVOS, respondVO)

		err = commRedisRpc.Device.Server.Report.Push(taskRespondVO)
		if err != nil {
			continue
		}
	}

}

func (e *deviceReportController) getReportOperateList(deviceEntity *edgeEntity.DeviceEntity) []*edgeEntity.OperateEntity {
	// 定义一个finder函数
	finder := func(entity commEntity.IEntity) bool {
		value := entity.(*edgeEntity.OperateEntity)
		if value.Manufacturer != deviceEntity.Manufacturer {
			return false
		}
		if value.DeviceType != deviceEntity.DeviceType {
			return false
		}
		if value.EngineType != "JavaScript" {
			return false
		}
		if value.ServiceType != "device" {
			return false
		}
		if value.OperateMode != "report" {
			return false
		}

		return true
	}

	// 查找数据
	var resultList []*edgeEntity.OperateEntity
	entityList := commRedisService.FindEntityList(edgeEntity.Type.OperateEntity.Type(), finder)
	for _, entity := range entityList {
		resultList = append(resultList, entity.(*edgeEntity.OperateEntity))
	}

	return resultList
}

func (e *deviceReportController) decodeReport(routineKey string, deviceEntity *edgeEntity.DeviceEntity, recv interface{}, param map[string]interface{}) (*commRedisRpc.OperateRespondVO, error) {
	// 获得相关的解码器
	operateEntityList := e.getReportOperateList(deviceEntity)
	if operateEntityList == nil || len(operateEntityList) == 0 {
		return nil, errors.New("找不到对应的解码器")
	}

	dat, err := deviceScript.ReportService.Decode(routineKey, deviceEntity.Manufacturer, deviceEntity.DeviceType, operateEntityList, recv, param)
	if err != nil {
		return nil, err
	}
	if dat == nil {
		return nil, errors.New("收到的数据，解码不成功")
	}

	// 构造上报给控制器的数据报文
	respondVO := &commRedisRpc.OperateRespondVO{}
	respondVO.Manufacturer = deviceEntity.Manufacturer
	respondVO.DeviceType = deviceEntity.DeviceType
	respondVO.DeviceName = deviceEntity.DeviceName
	respondVO.OperateMode = enumOperateMode.Report
	respondVO.Param = param

	respondVO.OperateName = dat[enumRecordData.OperateName].(string)

	status := make(map[string]interface{})
	status[enumDataCommStatus.CommSuccessTime] = time.Now().UnixMilli()
	status[enumDataCommStatus.CommFailedTime] = 0
	status[enumDataCommStatus.CommFailedCount] = 0

	data := make(map[string]interface{})
	data[enumDataCommStatus.CommValue] = dat[enumRecordData.Data]
	data[enumDataCommStatus.CommStatus] = status

	respondVO.Data = data

	respondVO.Code = http.StatusOK
	return respondVO, nil
}
